#pragma once

#include "sys/IInterface.h"

#include "boost/any.hpp"

#include "messenging/event/EventArgs.h"
#include "messenging/change/Observer.h"

typedef WORD vHotkey;
typedef HICON vSysICon;

/*!
	\brief define error key
*/
DEFINE_ERROR(vErr_MenunameConflict,		idspace_uiform, 1)
DEFINE_ERROR(vErr_ToolbarnameConflict, idspace_uiform, 2)
DEFINE_ERROR(vErr_ToolbarIDNone,			idspace_uiform, 3)
DEFINE_ERROR(vErr_HotkeyConflict,			idspace_uiform, 4)
DEFINE_ERROR(vErr_HotkeyInvalid,				idspace_uiform, 5)

typedef std::vector<IObject*> ControlList;
typedef std::vector<IObject*> ToolbarList;
typedef std::vector<IObject*> PaneList;

/*! \class Hotkey
*/
class Hotkey
{
public:
	static Hotkey Create(bool shift,bool ctrl,bool alt,vHotkey key)
	{
		static const wchar_t* CTRL = L"Ctrl";
		static const wchar_t* SHIFT = L"Shift";
		static const wchar_t* ALT = L"Alt";
		static const wchar_t* SEPERATOR = L"+";

		ASSERT(key!=L'\0');
		String text = L"";
		if(shift)	{ text += SHIFT; text += SEPERATOR; }
		if(ctrl)	{ text += CTRL; text += SEPERATOR; }
		if(alt)	{ text += ALT; text += SEPERATOR; }
		text += key;

		return Hotkey(shift,ctrl,alt,key,text);
	}
	static Hotkey CreateText(bool shift,bool ctrl,bool alt,vHotkey key,const String& hotkeytext)
	{
		ASSERT(key!=L'\0');
		return Hotkey(shift,ctrl,alt,key,hotkeytext);
	}
	Hotkey(){m_shift = false; m_ctrl = false; m_key = L'\0'; m_text = L"";}
	bool operator==(const Hotkey& other) const {return Equal(other);}
	bool operator<(const Hotkey& other) const {return m_key<other.m_key;}
	bool operator>(const Hotkey& other) const {return m_key>other.m_key;}
	bool Equal(const Hotkey& other) const {return (m_shift==other.m_shift) && (m_ctrl==other.m_ctrl) && (m_key==other.m_key);}
	bool IsNull() const {return m_key==L'\0';}
	bool IsShift() const {return m_shift;}
	bool IsCtrl() const {return m_ctrl;}
	bool IsAlt() const {return m_alt;}
	vHotkey GetKey() const {return m_key;}
	String GetText() const { return m_text; }

private:
	Hotkey(bool shift,bool ctrl,bool alt,vHotkey key,const String& text){m_shift = shift; m_ctrl = ctrl; m_alt = alt; m_key = key; m_text = text;}
	bool m_shift;
	bool m_ctrl;
	bool m_alt;
	vHotkey m_key;
	String m_text;
};

enum dockAction{
	da_dockLeftOf,
	da_dockTopOf,
	da_dockRightOf,
	da_dockBottomOf
};

enum showAction{
	sa_show,
	sa_hide,
	sa_showMaximize,
	sa_showMinimize
};

class PaneCreateEventArgs : EventArgs
{
public:
	PaneCreateEventArgs(uintptr parentwindow)
		:m_parentwindow(parentwindow)
	{
		m_window = NULL;
	}

	uintptr GetParentWindow() const {return m_parentwindow;}
	void AttachWindow(uintptr window) {m_window = window;}
	uintptr GetWindow() const {return m_window;}
	bool IsValid() const {return m_window!=NULL;}

private:
	uintptr m_parentwindow;
	uintptr m_window;
};

class UpdateEventArgs : EventArgs
{
public:
	UpdateEventArgs(const InterestedObjects& interestedObjects,IObject* subject,uint32 data)
		:m_interestedObjects(interestedObjects),
		m_subject(subject),
		m_data(data)
	{}

private:
	void operator=(const UpdateEventArgs& /*other*/){}
	const InterestedObjects& m_interestedObjects;
	IObject* m_subject;
	uint32 m_data;
};

class FormCreateEventArgs : public EventArgs
{
public:
	FormCreateEventArgs(IObject* form,uint32 category)
	{
		m_form = form;
		m_category = category;
	}
	IObject* GetForm() const{return m_form;}
	uint32 GetCategory() const {return m_category;}

private:
	IObject* m_form;
	uint32 m_category;
};

/*!\class Packet
	\brief for data exchange between UI and main program

	\warning Don't add special method here,such as GetColor()
			 You can GetCustomValue<Color>()
*/
class Packet
{
public:
	typedef boost::any PacketEntry;
	typedef std::vector<PacketEntry> PacketEntryList;

public:
	Packet(){}
	template<typename T0>
	Packet(T0 t0){
		AddEntry(t0);
	}
	template<typename T0,typename T1>
	Packet(T0 t0,T1 t1){
		AddEntry(t0,t1);
	}
	template<typename T0,typename T1,typename T2>
	Packet(T0 t0,T1 t1,T2 t2){
		AddEntry(t0,t1,t2);
	}
	template<typename T0,typename T1,typename T2,typename T3>
	Packet(T0 t0,T1 t1,T2 t2,T3 t3){
		AddEntry(t0,t1,t2,t3);
	}
	template<typename T0,typename T1,typename T2,typename T3,typename T4>
	Packet(T0 t0,T1 t1,T2 t2,T3 t3,T4 t4){
		AddEntry(t0,t1,t2,t3,t4);
	}
	template<typename T0,typename T1,typename T2,typename T3,typename T4,typename T5>
	Packet(T0 t0,T1 t1,T2 t2,T3 t3,T4 t4,T5 t5){
		AddEntry(t0,t1,t2,t3,t4,t5);
	}
	template<typename T0,typename T1,typename T2,typename T3,typename T4,typename T5,typename T6>
	Packet(T0 t0,T1 t1,T2 t2,T3 t3,T4 t4,T5 t5,T6 t6){
		AddEntry(t0,t1,t2,t3,t4,t5,t6);
	}
	template<typename T0,typename T1,typename T2,typename T3,typename T4,typename T5,typename T6,typename T7>
	Packet(T0 t0,T1 t1,T2 t2,T3 t3,T4 t4,T5 t5,T6 t6,T7 t7){
		AddEntry(t0,t1,t2,t3,t4,t5,t6,t7);
	}
	template<typename T0,typename T1,typename T2,typename T3,typename T4,typename T5,typename T6,typename T7,typename T8>
	Packet(T0 t0,T1 t1,T2 t2,T3 t3,T4 t4,T5 t5,T6 t6,T7 t7,T8 t8){
		AddEntry(t0,t1,t2,t3,t4,t5,t6,t7,t8);
	}
	template<typename T0,typename T1,typename T2,typename T3,typename T4,typename T5,typename T6,typename T7,typename T8,typename T9>
	Packet(T0 t0,T1 t1,T2 t2,T3 t3,T4 t4,T5 t5,T6 t6,T7 t7,T8 t8,T9 t9){
		AddEntry(t0,t1,t2,t3,t4,t5,t6,t7,t8,t9);
	}
	template<typename T0>
	void AddEntry(T0 t0){
		m_packetentries.push_back(t0);
	}
	template<typename T0,typename T1>
	void AddEntry(T0 t0,T1 t1){
		m_packetentries.push_back(t0);
		m_packetentries.push_back(t1);
	}
	template<typename T0,typename T1,typename T2>
	void AddEntry(T0 t0,T1 t1,T2 t2){
		m_packetentries.push_back(t0);
		m_packetentries.push_back(t1);
		m_packetentries.push_back(t2);
	}
	template<typename T0,typename T1,typename T2,typename T3>
	void AddEntry(T0 t0,T1 t1,T2 t2,T3 t3){
		m_packetentries.push_back(t0);
		m_packetentries.push_back(t1);
		m_packetentries.push_back(t2);
		m_packetentries.push_back(t3);
	}
	template<typename T0,typename T1,typename T2,typename T3,typename T4>
	void AddEntry(T0 t0,T1 t1,T2 t2,T3 t3,T4 t4){
		m_packetentries.push_back(t0);
		m_packetentries.push_back(t1);
		m_packetentries.push_back(t2);
		m_packetentries.push_back(t3);
		m_packetentries.push_back(t4);
	}
	template<typename T0,typename T1,typename T2,typename T3,typename T4,typename T5>
	void AddEntry(T0 t0,T1 t1,T2 t2,T3 t3,T4 t4,T5 t5){
		m_packetentries.push_back(t0);
		m_packetentries.push_back(t1);
		m_packetentries.push_back(t2);
		m_packetentries.push_back(t3);
		m_packetentries.push_back(t4);
		m_packetentries.push_back(t5);
	}
	template<typename T0,typename T1,typename T2,typename T3,typename T4,typename T5,typename T6>
	void AddEntry(T0 t0,T1 t1,T2 t2,T3 t3,T4 t4,T5 t5,T6 t6){
		m_packetentries.push_back(t0);
		m_packetentries.push_back(t1);
		m_packetentries.push_back(t2);
		m_packetentries.push_back(t3);
		m_packetentries.push_back(t4);
		m_packetentries.push_back(t5);
		m_packetentries.push_back(t6);
	}
	template<typename T0,typename T1,typename T2,typename T3,typename T4,typename T5,typename T6,typename T7>
	void AddEntry(T0 t0,T1 t1,T2 t2,T3 t3,T4 t4,T5 t5,T6 t6,T7 t7){
		m_packetentries.push_back(t0);
		m_packetentries.push_back(t1);
		m_packetentries.push_back(t2);
		m_packetentries.push_back(t3);
		m_packetentries.push_back(t4);
		m_packetentries.push_back(t5);
		m_packetentries.push_back(t6);
		m_packetentries.push_back(t7);
	}
	template<typename T0,typename T1,typename T2,typename T3,typename T4,typename T5,typename T6,typename T7,typename T8>
	void AddEntry(T0 t0,T1 t1,T2 t2,T3 t3,T4 t4,T5 t5,T6 t6,T7 t7,T8 t8){
		m_packetentries.push_back(t0);
		m_packetentries.push_back(t1);
		m_packetentries.push_back(t2);
		m_packetentries.push_back(t3);
		m_packetentries.push_back(t4);
		m_packetentries.push_back(t5);
		m_packetentries.push_back(t6);
		m_packetentries.push_back(t7);
		m_packetentries.push_back(t8);
	}
	template<typename T0,typename T1,typename T2,typename T3,typename T4,typename T5,typename T6,typename T7,typename T8,typename T9>
	void AddEntry(T0 t0,T1 t1,T2 t2,T3 t3,T4 t4,T5 t5,T6 t6,T7 t7,T8 t8,T9 t9){
		m_packetentries.push_back(t0);
		m_packetentries.push_back(t1);
		m_packetentries.push_back(t2);
		m_packetentries.push_back(t3);
		m_packetentries.push_back(t4);
		m_packetentries.push_back(t5);
		m_packetentries.push_back(t6);
		m_packetentries.push_back(t7);
		m_packetentries.push_back(t8);
		m_packetentries.push_back(t9);
	}
	real Getreal(uint32 index) const{return GetTypedValue<real>(index);}
	char Getint8(uint32 index) const{return GetTypedValue<char>(index);}
	short Getint16(uint32 index) const{return GetTypedValue<short>(index);}
	int32 Getint32(uint32 index) const{return GetTypedValue<int32>(index);}
	long Getlong(uint32 index) const{return GetTypedValue<long>(index);}
	byte Getuint8(uint32 index) const{return GetTypedValue<char>(index);}
	int16 Getuint16(uint32 index) const{return GetTypedValue<int16>(index);}
	uint32 Getuint32(uint32 index) const{return GetTypedValue<uint32>(index);}
	uint32 Getulong(uint32 index) const{return GetTypedValue<uint32>(index);}
	String Getstring(uint32 index) const{return GetTypedValue<String>(index);}
	template<typename T>
	T Getcustom(uint32 index) const{return GetTypedValue<T>(index);}
	uint32 GetCount() const {return m_packetentries.size();}
	void Clear(){m_packetentries.clear();}

private:
	template<typename T>
	inline T GetTypedValue(uint32 index) const
	{
		ASSERT(index < m_packetentries.size());
		return boost::any_cast<T>(m_packetentries[index]);
	}
	PacketEntryList m_packetentries;
};

class FormBase
{
public:
	void SendPacket(Packet* packet){m_packet = packet;}
	Packet* GetPacket()const{return m_packet;}

private:
	Packet* m_packet;
};

template<typename T>
inline IObject* _getself(void* obj)
{
	T* pifobj = (T*)obj;
	if (!pifobj)	
		return NULL;
	IObject* self = NULL;
	pifobj->QueryObject(&self);
	return self;
}